package at.technikum_wien.embsys.aat.PriscillaCore.component;

import java.util.List;

import at.technikum_wien.embsys.aat.PriscillaCore.enums.EnoceanComponentType;
import at.technikum_wien.embsys.aat.PriscillaCore.telegram.Telegram;



/**
 * 
 * EEP_07_12_03 component class - automated metering
 *
 * Type: automated meter reading - water
 * 
 * @author B. Aigner
 * 
 */
public class EEP_07_12_03 implements EnoceanComponent {
	
	Telegram telegram;
	List<?> eventListener;
	
	int value = -300;
	boolean currentValue;
	boolean cumulativeValue;
	int divisor = -300;
	int tariff = -300;
	
	
	EnoceanComponentType enoceanComponentType = EnoceanComponentType.EEP_07_12_03;
	boolean telegramCreation = false;

	/**
	 * This constructor is used for received packets.
	 * It will parse the telegram and set the corresponding members.
	 * 
	 * @param telegram Received Telegram
	 * @param listener Event subscriber list
	 */
	public EEP_07_12_03(Telegram telegram, List<?> listener) {
		super();
		this.telegram = telegram;
		this.eventListener = listener;
		
		switch(telegram.getData0() & 0x03) {
		case 0:
			divisor = 1;
			break;
		case 1:
			divisor = 10;
			break;
		case 2:
			divisor = 100;
			break;
		case 3:
			divisor = 1000;
			break;
		}
		
		value = (telegram.getData3() *  65536 + telegram.getData2() * 256 + telegram.getData1()) * divisor;
		
		tariff = (telegram.getData0() & 0xF0) / 16;
		
		if(checkBit(telegram.getData0(), 2)) {
			currentValue = true;
			cumulativeValue = false;
		} else {
			currentValue = false;
			cumulativeValue = true;
		}
		fireFrame();
	}

	/**
	 * Fire all associated events
	 */
	void fireFrame() {
		//TODO: Metering Event
		/*Iterator listen = eventListener.iterator();
		final FrameEventFan frameEventFan = new FrameEventFan(this, telegram.getDeviceID(), this.fanspeed, this.fantype );
		while (listen.hasNext()) {
			((LinkListener) listen.next()).frameReceived_Fan(frameEventFan);
		}
		*/
	}

	/**
	 * Void constructor. It is used to create a new telegram for sending
	 */
	public EEP_07_12_03() {
		super();
		telegram = new Telegram();
		telegramCreation = true;
	}

	/**
	 * This constructor is used to create a telegram (the device id is given as parameter)
	 * @param deviceID Full device ID
	 */
	public EEP_07_12_03(String deviceID) {
		super();
		telegram = new Telegram();
		telegram.setDeviceID(deviceID);
		telegramCreation = true;
	}
	
	boolean checkBit(int value, int bitNr) {
		return (value & (1 << bitNr)) != 0;
	}
	
	int setBit(int value, int bitNr) {
		return value | (1<<bitNr);
	}
	
	int clrBit(int value, int bitNr) {
		return value & (~(1<<bitNr));
	}
	
	@Override
	public String getDeviceID() {
		return telegram.getDeviceID();
	}
	@Override
	public String getORG() {
		return telegram.getxORG();
	}
	@Override
	public EnoceanComponentType getType() {
		return enoceanComponentType;
	}

	@Override
	public void setDeviceID(String deviceID) {
		telegram.setDeviceID(deviceID);
	}

	/**
	 * Creates a new telegram from the component
	 * 
	 * This method creates a new telegram (if the component is initialized with
	 * a constructor without a telegram as parameter) or returns the saved telegram.
	 * The new telegram is built up from the members in this class (in this case measuring values). 
	 * @return Created telegram
	 */
	public Telegram getTelegram() {
		if(telegramCreation == true) {
			telegram.setData3(((value/divisor)&0xFF0000)/65536);
			telegram.setData2(((value/divisor)&0x00FF00)/256);
			telegram.setData1((value/divisor)&0x0000FF);
			
			telegram.setData0(tariff*16 + divisor);
			
			if(currentValue == true) {
				telegram.setData0(setBit(telegram.getData0(),2));
			} else {
				telegram.setData0(clrBit(telegram.getData0(),2));
			}
		}
		return telegram;
	}

	public int getValue() {
		return value;
	}

	public boolean isCurrentValue() {
		return currentValue;
	}

	public boolean isCumulativeValue() {
		return cumulativeValue;
	}

	public int getDivisor() {
		return divisor;
	}

	public int getTariff() {
		return tariff;
	}

	public void setValue(int value) {
		if(value >= (2^24)) return;
		this.value = value;
	}

	public void setCurrentValue(boolean currentValue) {
		this.currentValue = currentValue;
		this.cumulativeValue = !currentValue;
	}

	public void setCumulativeValue(boolean cumulativeValue) {
		this.cumulativeValue = cumulativeValue;
		this.currentValue = !cumulativeValue;
	}

	public void setDivisor(int divisor) {
		if((divisor != 1) && (divisor != 10) && (divisor != 100) && (divisor != 1000)) return;
		this.divisor = divisor;
	}

	public void setTariff(int tariff) {
		if(tariff > 15) return;
		this.tariff = tariff;
	}
}
